#pragma once

#include "ProgramOptions.h"

#include <boost/progress.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dag_shortest_paths.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/bellman_ford_shortest_paths.hpp>
#include <boost/property_map/vector_property_map.hpp>
#include <boost/tuple/tuple_comparison.hpp>



#include <limits.h>

#include "lp_lib.h"

using namespace boost;

typedef adjacency_list<vecS, vecS, directedS, property<vertex_distance_t, float>, property<edge_weight_t, float> > graph_t;
typedef graph_traits<graph_t>::vertex_descriptor vertex_t;
typedef graph_traits<graph_t>::edge_descriptor edge_t;
typedef property_map<graph_t, vertex_distance_t>::type distance_map_t;
typedef property_map<graph_t, edge_weight_t>::type weight_map_t;
typedef property_map<graph_t, vertex_index_t>::type index_map_t;
typedef graph_traits<graph_t>::vertex_iterator vertex_iter;
typedef graph_traits<graph_t>::edge_iterator edge_iter;

typedef map<pair<int,int>, vector<AppearanceHist>> hist_map_t;
typedef ProgramOptions PO;

struct location 
{
	int ts;
	int x;
	int y;
};

class Batch
{
private:
	int batch_begin_frame, batch_num_of_frames, source, prev_source, batch_end_frame, vsink, batch_locations;
	double offset;
	PO * p_po;
	vector<location> sources, sources_backup;
	distance_map_t distance_map, distance_original;
	vector<vector<int>> prev_paths;
	graph_t g_original;
	vector<float> vertices;
	hist_map_t hist_map;
	map<pair<int,int>, vector<bool>> vis_map;

	void setWeightAndDistances( graph_t & g );

	bool withinRange( int range, int loc, int compare, pair<int,int> & diff );

	void getObjectAppearance( int location, vector<AppearanceHist> & app, vector<bool> & cameraVisObj, 
								vector<img::ImageRGB> & ims );

	double getAppearanceValue( int group, int location, vector<img::ImageRGB> & ims );

	void getVerticesInRange( int vertex, pair<int,int> diff, vector<int> & extraVertices, map<int, bool> & availableVertices );

	pair<int,int> intToXY( int i );

	int locationToInt( location l );

	void reconstructPath( vector<size_t> & predecessorMap , int source , int vsink , vector<int> & path );

	/*void calculateCostsAppearance( float cost, int frame, int location, vector<int> & neighbours, vector<img::ImageRGB> & ims1, 
							  vector<img::ImageRGB> & ims2, vector<float> & costs );*/

	/*void computeBhattacharyyaCoefficients( vector<AppearanceHist> & appearance, 
		vector<vector<AppearanceHist>> & neighbourAppearances, vector<float> & distances );*/

	void copy_weight_and_distance_map( graph_t & g , map<pair<int, int>,double> & weights , distance_map_t & distance_map, 
								  vector_property_map<double> & distances );

	void createGraph( graph_t & g );

	int locationOf( int toSearch, vector<int> path );

	void find_leave_point( vector<int> & path, vector<int> & competing_path, int hit_location, signed int & leave_location, 
								signed int & split_location );

	void find_and_remove_competing_path( int vertex , unsigned int & continueLocation, vector<int> & toReturn );

	void find_shortest_path_dag( graph_t & g, vector<int> & path );

	void find_shortest_path_dijkstra( graph_t & g, vector<int> & path );

	void getAppearance( int frame, rectangle r, img::ImageRGB & im, img::ImageRGB & background, AppearanceHist & apHist );

	void getAppearance2( int frame, int location, vector<img::ImageRGB> & ims, vector<AppearanceHist> & appearance,
						  vector<bool> & visibility );

	void getImages( int frame, vector<img::ImageRGB> & ims );

	void getImagesLab( int frame, vector<ImageLab> & ims_out );

	int intToTimestep( int i );

	void extendGraph( graph_t & g, map<int,int> & vertexPairs);

	void extendGraphPath( graph_t & g, vector<int> & path, map<int,int> & vertexPairs );

	void findVertices( vector<int> & LP_vertices, map<int, bool> & availableVertices );

	void getNeighbours( int location, vector<int> & neighbours );

	double getProbability( int frame, int location, unsigned int range );

	void getShortestPath( graph_t & g, vector<int> & path );

	void getSource();

	void interlace_and_augment( vector<int> & path );

	float pathCost( vector<int> & path, weight_map_t & weight_map );

	float pathsCost();

	void readFile( int frame, vector<float> & proba );

	void readFiles();

	void reweighCosts( float cost, vector<float> & distances, vector<float> & costs );

	void setBatchLimits( PO & po, int begin_frame_counter, int & batch_begin_frame, int & batch_num_of_frames );

	//void transformEdgeCost( graph_t & g , map<pair<int,int>, double> & weights, vector_property_map<double> & distance_map, 
	//					 map<int,int> & vertexPairs );

	void transformEdgeCost( graph_t & g );

	bool isOccluded( int frame, int location, int cam );

	void removeSourceNode( int toRemove );

	void removeSourceConnections( graph_t & g );

public:
	vector<vector<int>> paths;
	vector<vector<int>> paths_shitrit;

	void shitrit( vector<pair<int,int>> & source_group );
	
	Batch( PO & po, int begin_frame_counter, vector<location> sources_in );
};